#include <string>
#include <csignal>
#include "reader_buf.h"
#include "spdlog/spdlog.h"

namespace simple {
    ReaderBuff::ReaderBuff(int read_fd) : read_fd_(read_fd) {
        this->buff_data_ = new char[this->buff_size_];
    }

    ReaderBuff::ReaderBuff(int read_fd, int buff_size) : read_fd_(read_fd), buff_size_(buff_size) {
        this->buff_data_ = new char[this->buff_size_];
    }

    int ReaderBuff::readFD() {
        if (this->buffered() > 0) {
            // 缓冲区还有数据, 不触发从句柄读取
            return 0;
        }
        // 缓冲区没有数据, 总是起始位置写入
        this->write_index = 0;
        this->read_index = 0;
        int size = (int) read(this->read_fd_, this->buff_data_, (this->buff_size_ - this->write_index));
        if (size <= -1) {
            spdlog::warn("read exception from io handle {}, {}.", this->read_fd_, strerror(errno));
            return -1;
        } else {
            this->write_index += size;
            return size;
        }
    }

    int ReaderBuff::readFDForce() {
        if (this->buff_size_ == this->write_index) {
            return 0;
        }
        if ((this->buff_size_ / 2) > this->buffered() && this->buffered() > 0) {
            // 缓冲区半空闲, 则将缓冲区后半部分移动到缓冲区前部
            memcpy(this->buff_data_, (this->buff_data_ + this->read_index), this->buffered());
            this->read_index = 0;
            this->write_index = this->buffered();
        }

        int size = (int) read(this->read_fd_, this->buff_data_+this->write_index, (this->buff_size_ - this->write_index));
        if (size <= -1) {
            spdlog::warn("read exception from io handle {}, {}.", this->read_fd_, strerror(errno));
            return -1;
        } else {
            this->write_index += size;
            return size;
        }
    }

    int ReaderBuff::readBuff(void *dest, int size) {
        if (size <= 0) {
            return 0;
        }
        if (size <= (this->write_index - this->read_index)) {
            char *source = this->buff_data_ + this->read_index;
            memcpy(dest, source, size);
            this->read_index += size;
            return size;
        }
        spdlog::error("ReaderBuff, Read buffer out of bounds");
        return -1;
    }

    int ReaderBuff::readByte(void *dest_ptr) {
        if (this->readFD() == -1) {
            return -1;
        }
        if (this->buffered() > 0) {
            return this->readBuff(dest_ptr, 1);
        }
        return 0;
    }

    int ReaderBuff::readBytes(void *dest, int size) {
        int readOffset = 0;
        while (readOffset < size) {
            if (this->readFD() == -1) {
                return -1;
            } else if (this->buffered() <= 0) {
                return readOffset;
            }

            char *dest_ptr = (char *) dest + readOffset;
            int bytes_written = size - readOffset;
            if (bytes_written > this->buffered()) {
                // 缓冲区数据不足, 只读能取一部分
                bytes_written = this->buffered();
            }
            if (this->readBuff(dest_ptr, bytes_written)) {
                readOffset += bytes_written;
            } else {
                break;
            }
        }
        return readOffset;
    }

    std::string ReaderBuff::readLine() {
        std::vector<char> buf;
        if ((this->readLine(buf, this->buff_size_)) > 0) {
            std::string str(buf.begin(), buf.end());
            return str;
        } else {
            return "";
        }
    }

    int ReaderBuff::readLine(std::vector<char> &buf) {
        return this->readLine(buf, this->buff_size_);
    }

    int ReaderBuff::readLine(std::vector<char> &buf, int maxLength) {
        if (this->readFDForce() == -1) {
            return -1;
        } else if (this->buffered() <= 0) {
            return 0;
        } else if (maxLength > this->buffered()) {
            maxLength = this->buffered();
        }

        buf.clear();
        bool flag = false;
        for (int i = 0; i < maxLength; ++i) {
            char *current = this->buff_data_ + this->read_index + i;
            if (*current == '\n') {
                this->read_index += i + 1;
                flag = true;
                break;
            }
            if (*current == '\r' && *(current + 1) == '\n') {
                this->read_index += i + 2;
                flag = true;
                break;
            }
            buf.push_back(*current);
        }
        if (flag) {
            return (int) buf.size();
        }
        return 0;
    }

    int ReaderBuff::peek(void *dest, int size) {
        if (this->readFDForce() == -1) {
            return -1;
        } else if (this->buffered() <= 0) {
            return 0;
        } else if (size > this->buffered()) {
            size = this->buffered();
        }

        char *source_ptr = this->buff_data_ + this->read_index;
        memcpy(dest, source_ptr, size);
        return size;
    }

    int ReaderBuff::peek(std::vector<char> &buf, int size) {
        if (this->readFDForce() == -1) {
            return -1;
        } else if (this->buffered() <= 0) {
            return 0;
        } else if (size > this->buffered()) {
            size = this->buffered();
        }
        buf.clear();
        buf.assign((this->buff_data_ + this->read_index), (this->buff_data_ + this->read_index + size));
        return size;
    }

    int ReaderBuff::buffered() const {
        return this->write_index - this->read_index;
    }

    int ReaderBuff::size() const {
        return this->buff_size_;
    }

    void ReaderBuff::reset() {
        this->write_index = -1;
        this->read_index = -1;
    }
}